#ifndef TCPCLIENT_HPP
#define TCPCLIENT_HPP
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>

#include <cstring>
#include <iostream>
#include <string>

class TcpClient
{
public:
  TcpClient(const std::string &ip, int16_t port)
      : sockfd_(-1), ip_(ip), port_(port), isreconnect_(false), isrunning_(false) {}

  void Init()
  {
    // 创建TCP套接字
    sockfd_ = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd_ < 0)
    {
      printf("socket error , error message: %s\n", strerror(errno));
      exit(2);
    }


  }

  void Request()
  {
    std::string request;
    char buff[4096];

    // 发起请求
    std::cout << "Please Enter# ";
    std::getline(std::cin, request);
    int n = write(sockfd_, request.c_str(), request.size());
    if (n < 0)
    {
      std::cerr << "warning write err..." << std::endl;
      return; // 写入失败时本次操作就没有必要了
    }

    // 接收响应
    n = read(sockfd_, buff, sizeof(buff));
    if (n > 0)
    {
      buff[n] = 0;
      std::cout << buff << std::endl;
    }
    else if (n == 0)
    {
      std::cout << "Server exit...." << std::endl;
    }
    else
    {
      printf("Client read error, error message: %s\n", strerror(errno));
    }
  }

  void Start()
  {

    // 对服务端发起连接 请求 以及接收服务端的响应

    // 发起连接
    isrunning_ = true;
    struct sockaddr_in server;

    memset(&server, 0, sizeof(server));

    server.sin_family = AF_INET;
    inet_pton(AF_INET, ip_.c_str(), &(server.sin_addr));
    server.sin_port = htons(port_);
    socklen_t len = sizeof(server);
    int reconnectcnt = 5;
    do
    {
      if (connect(sockfd_, (sockaddr *)&server, len))
      {
        printf("connect error, reconnecting(%d)...\n",reconnectcnt);
        isreconnect_ = true;
        reconnectcnt--;
        sleep(1);
      }
      else
      {
        isreconnect_ = false;
      }
    } while (isreconnect_ && reconnectcnt);
    if (reconnectcnt == 0)
    {
      printf("user offline...\n");
      isrunning_ = false;
      return;
    }
    Request();
  }

  ~TcpClient()
  {
    // 关闭无用的TCP套接字描述符
    if (sockfd_ != -1)
    {
      close(sockfd_);
      sockfd_ = -1;
    }
    isrunning_ = false;
  }
  bool GetRunningStat()
  {
    return isrunning_;
  }

private:
  int sockfd_;     // 套接字描述符
  std::string ip_; // 用户传递的IP地址
  int16_t port_;   // 用户传入的端口号
  bool isreconnect_;
  bool isrunning_;
};
#endif